//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<CEffectVariable10.cpp>
///	@path	~/src/graphics/dx10/
///	@date	2008/12/20
///	@desc	.

#include "config/config.h"

#include "lib/utilities/debug.h"
#include "lib/system/thread_debug.h"

#include "graphics/DxHelpers.h"
#include "graphics/IRenderTarget.h"
#include "graphics/dx10/CTexture2D10.h"
#include "graphics/dx10/CEffectVariable10.h"

namespace xeres {

	IMPL_IOBJECT_CLASS( CEffectVariable10 );

	// ctor
	CEffectVariable10::CEffectVariable10( RefWeak<CEffect10> effect , ID3D10EffectVariable * param )
		: m_effect( effect )
		, m_pParam( param )
	{
		memset( &m_desc , 0 , sizeof(D3D10_EFFECT_VARIABLE_DESC) );

		// get desc
		HRESULT hr = S_OK;
		hr = m_pParam->GetDesc( &m_desc );
	}

	// dtor
	CEffectVariable10::~CEffectVariable10( void )
	{
		if( m_effect.IsValid() )
		{
			m_effect->UnusedVariable( this );
		}
	}

	RefPass< IObject > CEffectVariable10::GetMaster( void )
	{
		return m_effect;
	}

	bool CEffectVariable10::SetByVar( RefWeak< IVar > var )
	{
		//
		return false;
	}

	// SetByData
	bool CEffectVariable10::SetByData( const void * data , size_t bytes )
	{
		HRESULT hr = m_pParam->SetRawValue( const_cast<void*>(data) , 0 , bytes );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CEffectVariable10::SetByData: Failed to set variable: %s.") ,
				d3d_get_err(hr) );
			return false;
		}
		return true;
	}

	// SetByTexture
	bool CEffectVariable10::SetByTexture( RefWeak< ITexture > texture )
	{
		ID3D10ShaderResourceView * pView = NULL;
		if( texture.IsValid() )
		{
			texture->GetTextureInterface()->QueryInterface( IID_ID3D10ShaderResourceView , (void**)&pView );
		}
		HRESULT hr = m_pParam->AsShaderResource()->SetResource( pView );
		if( pView )
			pView->Release();
		pView = NULL;
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CEffectVariable10::SetByTexture: Failed to set variable: %s.") ,
				d3d_get_err(hr) );
			return false;
		}
		return true;
	}
	// SetByRenderTarget
	bool CEffectVariable10::SetByRenderTarget( RefWeak< IRenderTarget > rt )
	{
		ID3D10RenderTargetView * pView = NULL;
		if( rt.IsValid() )
		{
			rt->GetRenderTargetInterface()->QueryInterface( IID_ID3D10RenderTargetView , (void**)&pView );
		}
		HRESULT hr = m_pParam->AsRenderTargetView()->SetRenderTarget( pView );
		if( pView )
			pView->Release();
		pView = NULL;
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CEffectVariable10::SetByRenderTarget: Failed to set variable: %s.") ,
				d3d_get_err(hr) );
			return false;
		}
		return true;
	}
	// GetVarTypeName
	const WString& CEffectVariable10::GetVarTypeName( void ) const
	{
		static const WString s_defaultName( _S("") );
		return s_defaultName;
	}
	// GetVarTypeID
	const ClassID CEffectVariable10::GetVarTypeID( void ) const
	{
		ID3D10EffectType * type = m_pParam->GetType();
		D3D10_EFFECT_TYPE_DESC desc;
		type->GetDesc( &desc );
		switch( desc.Type )
		{
		case D3D10_SVT_BOOL:
			if( desc.Class == D3D10_SVC_SCALAR )
				return BOOL_TYPE_CLASS_ID;
			break;
		case D3D10_SVT_INT:
			if( desc.Class == D3D10_SVC_SCALAR )
				return INT_TYPE_CLASS_ID;
			break;
		case D3D10_SVT_FLOAT:
			if( desc.Class == D3D10_SVC_SCALAR )
				return FLOAT_TYPE_CLASS_ID;
			if( desc.Type == D3D10_SVC_VECTOR ) {
				if( desc.Elements == 3 )
					return VECTOR_TYPE_CLASS_ID;
				else if( desc.Elements == 4 )
					return COLOR_TYPE_CLASS_ID;
			} else if( desc.Class == D3D10_SVC_MATRIX_ROWS ) {
				return MATRIX_TYPE_CLASS_ID;
			}
			break;
		case D3D10_SVT_STRING:
			if( desc.Class == D3D10_SVC_SCALAR )
				return STRING_TYPE_CLASS_ID;
			break;
		}
		return VOID_TYPE_CLASS_ID;
	}
	// DuplicateFrom
	bool CEffectVariable10::DuplicateFrom( const Ref<IVar>& val )
	{
		return false;
	}
	// SetBool
	bool CEffectVariable10::SetBool( bool val )
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		if( scalar )
			return SUCCEEDED( scalar->SetBool( val ? TRUE : FALSE ) );
		return false;
	}
	// SetInt
	bool CEffectVariable10::SetInt( int val )
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		if( scalar )
			return SUCCEEDED( scalar->SetInt( val ) );
		return false;
	}
	// SetFloat
	bool CEffectVariable10::SetFloat( float val )
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		if( scalar )
			return SUCCEEDED( scalar->SetFloat( val ) );
		return false;
	}
	// SetPair
	bool CEffectVariable10::SetPair( const Pair<float>& val )
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		if( scalar )
			return SUCCEEDED( scalar->SetFloatArray( (float*)val.f , 0 , 2 ) );
		return false;
	}
	// SetVector
	bool CEffectVariable10::SetVector( const Vector<float>& val )
	{
		D3DXVECTOR4 vec( val.x , val.y , val.z , 1 );
		ID3D10EffectVectorVariable * v = m_pParam->AsVector();
		if( v )
			return SUCCEEDED( v->SetFloatVector( (float*)&vec ) );
		return false;
	}
	// SetQuat
	bool CEffectVariable10::SetQuat( const Quat<float>& val )
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		if( scalar )
			return SUCCEEDED( scalar->SetFloatArray( (float*)val.f , 0 , 4 ) );
		return false;
	}
	// SetColor
	bool CEffectVariable10::SetColor( const Color4& val )
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		if( scalar )
			return SUCCEEDED( scalar->SetFloatArray( (float*)val.c , 0 , 4 ) );
		return false;
	}
	// SetMatrix
	bool CEffectVariable10::SetMatrix( const Matrix<float>& val )
	{
		ID3D10EffectMatrixVariable * mat = m_pParam->AsMatrix();
		if( mat )
			return SUCCEEDED( mat->SetMatrix( (float*)val.m16 ) );
		return false;
	}
	// SetString
	bool CEffectVariable10::SetString( const WString& val )
	{
		return false;
	}
	// SetObject
	bool CEffectVariable10::SetObject( RefWeak<IObject> val )
	{
		if( val->IsA<ITexture>() )
		{
			if( val->IsA<IRenderTarget>() )
			{
				return SetByRenderTarget( RefWeak<IRenderTarget>(val) );
			}
			return SetByTexture( RefWeak<ITexture>(val) );
		}
		return false;
	}
	// GetBool
	bool CEffectVariable10::GetBool( bool& val ) const
	{
		BOOL proxy;
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		if( scalar && SUCCEEDED( scalar->GetBool( &proxy ) ) )
		{
			val = proxy ? true : false;
			return true;
		}
		return false;
	}
	// GetInt
	bool CEffectVariable10::GetInt( int& val ) const
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		return ( scalar && SUCCEEDED( scalar->GetInt( &val ) ) );
	}
	// GetFloat
	bool CEffectVariable10::GetFloat( float& val ) const
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		return ( scalar && SUCCEEDED( scalar->GetFloat( &val ) ) );
	}
	// GetPair
	bool CEffectVariable10::GetPair( Pair<float>& val ) const
	{
		FLOAT ff[2];
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		if( scalar && SUCCEEDED( scalar->GetFloatArray( ff , 0 , 2 ) ) )
		{
			val.copy( ff );
			return true;
		}
		return false;
	}
	// GetVector
	bool CEffectVariable10::GetVector( Vector<float>& val ) const
	{
		FLOAT ff[4];
		ID3D10EffectVectorVariable * v = m_pParam->AsVector();
		if( v && SUCCEEDED( v->SetFloatVector( ff ) ) )
		{
			val.copy( ff );
			return true;
		}
		return false;
	}
	// GetQuat
	bool CEffectVariable10::GetQuat( Quat<float>& val ) const
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		return ( scalar && SUCCEEDED( scalar->GetFloatArray( val.f , 0 , 4 ) ) );
	}
	// GetColor
	bool CEffectVariable10::GetColor( Color4& val ) const
	{
		ID3D10EffectScalarVariable * scalar = m_pParam->AsScalar();
		return ( scalar && SUCCEEDED( scalar->GetFloatArray( val.c , 0 , 4 ) ) );
	}
	// GetMatrix
	bool CEffectVariable10::GetMatrix( Matrix<float>& val ) const
	{
		ID3D10EffectMatrixVariable * mat = m_pParam->AsMatrix();
		return ( mat && SUCCEEDED( mat->GetMatrix( val.m16 ) ) );
	}
	// GetString
	bool CEffectVariable10::GetString( WString& val ) const
	{
		LPCSTR pStr = NULL;
		ID3D10EffectStringVariable * s = m_pParam->AsString();
		if( s && SUCCEEDED( s->GetString( &pStr ) ) )
		{
			mbs_to_wcs( pStr , val );
			return true;
		}
		return false;
	}
	// GetObject
	bool CEffectVariable10::GetObject( Ref<IObject>& val ) const
	{
		return false;
	}
} // namespace xeres
